using System;
using Mono.Fuse;
using Mono.Unix.Native;
using System.Collections;
using System.Collections.Generic;

namespace Mehat.San.SanFS
{

	public class SanFS : FileSystem
	{
		public static SanFS		Application;

		public SanFS()
		{
			DirEntFactory.Initialize();
			VirtualMountManager.Initialize();
			SystemDirectory.Initialize();
			ConfigurationManager.Initialize();
		}

		static void Main(string[] Args)
		{
			if (Args.Length < 1)
			{
				Console.WriteLine("Error: Must specify a directory to mount at");
				return;
			}

			Application = new SanFS();
			Application.MountPoint = Args[0];
			//Application.EnableFuseDebugOutput = true;
			Application.Start();
		}

		protected override Errno OnAccessPath(string Path, AccessModes Mode)
		{
			return Errno.EIO;
		}

		protected override Errno OnChangePathPermissions(string Path, FilePermissions Perms)
		{
			return Errno.EIO;
		}

		protected override Errno OnChangePathTimes(string Path, ref Utimbuf Time)
		{
			return Errno.EIO;
		}

		protected override Errno OnCreateDirectory(string Path, FilePermissions Perms)
		{
			return Errno.EIO;
		}

		protected override Errno OnCreateHandle(string Path, OpenedPathInfo Info, FilePermissions Perms)
		{
			return Errno.EIO;
		}

		protected override Errno OnCreateHardLink(string OldPath, string Link)
		{
			return Errno.EIO;
		}

		protected override Errno OnCreateSpecialFile(string Path, FilePermissions Perms, ulong Device)
		{
			return Errno.EIO;
		}

		protected override Errno OnCreateSymbolicLink(string Target, string Link)
		{
			return Errno.EIO;
		}

		protected override Errno OnFlushHandle(string Path, OpenedPathInfo Info)
		{
			try
			{
				FileHandle	fh = FileHandleManager.Lookup(Info.Handle.ToInt32());
				
				ConfigurationManager.ActiveCachePolicy.FlushFile(fh);
				return 0;
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
				throw;
			}
		}

		protected override Errno OnGetFileSystemStatus(string Path, out Statvfs Buffer)
		{
			Buffer = new Statvfs();
			return Errno.EIO;
		}

		protected override Errno OnGetHandleStatus(string Path, OpenedPathInfo Info, out Stat StatBuffer)
		{
			StatBuffer = new Stat();
			return Errno.EIO;
		}

		protected override Errno OnGetPathStatus(string Path, out Stat StatBuffer)
		{
			StatBuffer = new Stat();
			
			try
			{
				StatBuffer = DirEntFactory.Lookup(Path).Stat;		
			}
			catch (KeyNotFoundException)
			{
				return Errno.ENOENT;
			}
			return 0;
		}

		protected override Errno OnOpenHandle(string Path, OpenedPathInfo Info)
		{
			FileHandle	fh = null;
			try
			{
				IDirectoryEntry	ent = DirEntFactory.Lookup(Path);
				fh = FileHandleManager.CreateHandle((IFile) ent, Info);
				ConfigurationManager.ActiveCachePolicy.OpenFile(fh);
				return 0;
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
				if (fh != null)
				{
					if (fh.State == EFileHandleState.Connected)
						ConfigurationManager.ActiveCachePolicy.ReleaseFile(fh);
					FileHandleManager.DestroyHandle(fh);
				}
				
				if (ex is KeyNotFoundException)
					return Errno.ENOENT;
				throw;
			}
		}
		
		protected override Errno OnReleaseHandle(string Path, OpenedPathInfo Info)
		{
			try
			{
				FileHandle	fh = FileHandleManager.Lookup(Info.Handle.ToInt32());
				ConfigurationManager.ActiveCachePolicy.ReleaseFile(fh);
				FileHandleManager.DestroyHandle(fh);
				return 0;
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
				throw;
			}
		}

		protected override Errno OnReadDirectory(string Path, OpenedPathInfo Info, out IEnumerable<Mono.Fuse.DirectoryEntry> Paths)
		{
			List<Mono.Fuse.DirectoryEntry> tmp = new List<Mono.Fuse.DirectoryEntry>();
			Paths = tmp;
			try
			{
				IDirectory	ent = (IDirectory) DirEntFactory.Lookup(Path);
					
				ent.Lock.WaitOne();
				try
				{	
					tmp.Add((DirectoryEntry) ent.Children["."]);
					tmp.Add((DirectoryEntry) ent.Children[".."]);
					foreach (IDirectoryEntry child in ent.Children.Values)
					{
						if (child.Name == "." || child.Name == "..")
							continue;
						tmp.Add((DirectoryEntry) child);
					}
				}
				catch
				{
					throw;
				}
				finally
				{
					ent.Lock.ReleaseMutex();
				}
				
			}
			catch (KeyNotFoundException)
			{
				return Errno.ENOENT;
			}
			
			return 0;
		}

		protected override Errno OnReadHandle(string Path, OpenedPathInfo Info, byte[] Buffer, long Offset, out int BytesRead)
		{
			try
			{
				FileHandle	fh = FileHandleManager.Lookup(Info.Handle.ToInt32());
				BytesRead = (int) ConfigurationManager.ActiveCachePolicy.ReadFile(fh, Buffer, Offset); 
				return 0;
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex);
				throw;
			}
		}

		protected override Errno OnReadSymbolicLink(string Path, out string Target)
		{
			Target = null;
			return Errno.EIO;
		}

		protected override Errno OnRemoveDirectory(string Path)
		{
			return Errno.EIO;
		}

		protected override Errno OnRemoveFile(string Path)
		{
			return Errno.EIO;
		}

		protected override Errno OnRemovePathExtendedAttribute(string Path, string Attribute)
		{
			return Errno.EIO;
		}

		protected override Errno OnRenamePath(string OldPath, string NewPath)
		{
			return Errno.EIO;
		}

		protected override Errno OnSetPathExtendedAttribute(string Path, string Attribute, byte[] Value, XattrFlags Flags)
		{
			return Errno.EIO;
		}

		protected override Errno OnSynchronizeDirectory(string Path, OpenedPathInfo Info, bool OnlyUserData)
		{
			return Errno.EIO;
		}

		protected override Errno OnSynchronizeHandle(string Path, OpenedPathInfo Info, bool OnlyUserData)
		{
			return Errno.EIO;
		}

		protected override Errno OnTruncateFile(string Path, long Length)
		{
			return Errno.EIO;
		}

		protected override Errno OnTruncateHandle(string Path, OpenedPathInfo Info, long Length)
		{
			return Errno.EIO;
		}

		protected override Errno OnWriteHandle(string Path, OpenedPathInfo Info, byte[] Buffer, long Offset, out int BytesWritten)
		{
			BytesWritten = 0;
			return Errno.EIO;
		}

	}	// END CLASS
}	// END NAMESPACE
